#if !defined(EXCEPTION_DLG_H)
#define EXCEPTION_DLG_H

#include "WinUtil.h"
#include "../client/ResourceManager.h"

typedef ULONG(WINAPI *RTLNTSTATUSTODOSERROR)(DWORD Status);

void GuiUninit(void* pParam);

class CExceptionDlg : public CDialogImpl<CExceptionDlg>
{
	public:
		enum { IDD = IDD_EXCEPTION };
		CExceptionDlg(LPEXCEPTION_POINTERS Exception, bool bDumped, DWORD dwDumpError) : m_pException(Exception), m_bDumped(bDumped), m_dwDumpError(dwDumpError) { };
		
		~CExceptionDlg()
		{
		};
		
		BEGIN_MSG_MAP(CExceptionDlg)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		COMMAND_HANDLER(IDC_COPY_EXCEPTION, BN_CLICKED, OnCopyException)
		COMMAND_HANDLER(IDOK, BN_CLICKED, OnContinue)
		COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnTerminate)
		END_MSG_MAP()
		
		void CopyEditToClipboard(HWND hWnd)
		{
			SendMessage(hWnd, EM_SETSEL, 0, 65535L);
			SendMessage(hWnd, WM_COPY, 0 , 0);
			SendMessage(hWnd, EM_SETSEL, 0, 0);
		}
		
		std::wstring FormatExceptionMessage()
		{
			std::wstring str;
			
			LPCWSTR pFmt = NULL;
			
			if (m_pException->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
			{
				DWORD_PTR dwAddress = 0;
				if (m_pException->ExceptionRecord->NumberParameters == 2)
				{
					if (m_pException->ExceptionRecord->ExceptionInformation[0] == 0)
						pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0xC0000005: Access violation reading 0x%08Ix.";
					else if (m_pException->ExceptionRecord->ExceptionInformation[0] == 8)
						pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0xC0000005: Access violation DEP 0x%08Ix.";
					else
						pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0xC0000005: Access violation writing 0x%08Ix.";
						
					dwAddress = m_pException->ExceptionRecord->ExceptionInformation[1];
				}
				else
					pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0xC0000005: Access violation";
					
				str.resize(95); //TODO
				wsprintf(&str.at(0), pFmt, m_pException->ExceptionRecord->ExceptionAddress, dwAddress);
				dcassert(str.size() > str.length());
			}
			else if (m_pException->ExceptionRecord->ExceptionCode == EXCEPTION_IN_PAGE_ERROR)
			{
				DWORD_PTR dwAddress = 0;
				DWORD_PTR dwCode = 0;
				if (m_pException->ExceptionRecord->NumberParameters == 3)
				{
					if (m_pException->ExceptionRecord->ExceptionInformation[0] == 0)
						pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0xC0000006: Page fault reading 0x%08Ix with code 0x%08Ix.";
					else if (m_pException->ExceptionRecord->ExceptionInformation[0] == 8)
						pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0xC0000006: Page fault DEP 0x%08Ix with code 0x%08Ix.";
					else
						pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0xC0000006: Page fault writing 0x%08Ix with code 0x%08Ix.";
						
					dwAddress = m_pException->ExceptionRecord->ExceptionInformation[1];
					dwCode = m_pException->ExceptionRecord->ExceptionInformation[3];
				}
				else
					pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0xC0000006: Page fault";
					
				str.resize(115); //TODO
				wsprintf(&str.at(0), pFmt, m_pException->ExceptionRecord->ExceptionAddress, dwAddress, dwCode);
				dcassert(str.size() > (size_t)str.length());
			}
			else
			{
				LPWSTR pMessage = NULL;
				int iMsgLen = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER, GetModuleHandle(L"ntdll.dll"), m_pException->ExceptionRecord->ExceptionCode, 0, (LPWSTR) & pMessage, 0, NULL);
				
				if (pMessage)
					pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0x%08x: %s";
				else
					pFmt = L"Unhandled exception at 0x%08Ix:\r\nCode 0x%08x";
					
				str.resize(55 + iMsgLen); //TODO
				wsprintf(&str.at(0), pFmt, m_pException->ExceptionRecord->ExceptionAddress, m_pException->ExceptionRecord->ExceptionCode, pMessage);
				dcassert(str.size() > (size_t)str.length());
				
				if (pMessage)
					LocalFree(pMessage);
			}
			
			return str;
		}
		
		LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
		{
			// Translate Dialog
			SetWindowText(CTSTRING(EXCEPTION_DIALOG));
			SetDlgItemText(IDC_EXCEPTION_HEADER, CTSTRING(EXCEPTION_HEADER));
			if (m_bDumped)
				SetDlgItemText(IDC_EXCEPTION_FOOTER, CTSTRING(EXCEPTION_FOOTER));
			else
			{
				std::wstring strError;
				strError.resize(32);
				wsprintf(&strError.at(0), L" (%i)", m_dwDumpError);
				SetDlgItemText(IDC_EXCEPTION_FOOTER, (TSTRING(EXCEPTION_FOOTER_FAIL) + _T(" ") + strError).c_str());
			}
			SetDlgItemText(IDC_EXCEPTION_RESTART, CTSTRING(EXCEPTION_RESTART));
			SetDlgItemText(IDC_COPY_EXCEPTION, CTSTRING(EXCEPTION_COPY));
			SetDlgItemText(IDOK, CTSTRING(EXCEPTION_CONTINUE));
			SetDlgItemText(IDCANCEL, CTSTRING(EXCEPTION_TERMINATE));
			
			m_hIcon = std::unique_ptr<HIconWrapper>(new HIconWrapper(IDR_ERROR));
			SetIcon(*m_hIcon, FALSE);
			SetIcon(*m_hIcon, TRUE);
			
			CenterWindow();
			CEdit ctrlEI(GetDlgItem(IDC_EXCEPTION_DETAILS));
			ctrlEI.FmtLines(TRUE);
			ctrlEI.AppendText(L_VERSIONSTRING, FALSE);
			ctrlEI.AppendText(_T(" \r\n"), FALSE);
			ctrlEI.AppendText(FormatExceptionMessage().c_str(), FALSE);
			extern string  g_cur_mediainfo_file;
			if (!g_cur_mediainfo_file.empty())
			{
				string l_mediainfo_tmp = "crash mediainfo file: " + g_cur_mediainfo_file;
				ctrlEI.AppendText(Text::toT(l_mediainfo_tmp).c_str(), FALSE);
			}
			ctrlEI.Detach();
			return TRUE;
		}
		
		LRESULT OnCopyException(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			CopyEditToClipboard(GetDlgItem(IDC_EXCEPTION_DETAILS));
			return 0;
		}
		
		LRESULT OnContinue(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			EndDialog(IDOK);
			return 0;
		}
		
		LRESULT OnTerminate(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			if (IsDlgButtonChecked(IDC_EXCEPTION_RESTART) == BST_CHECKED)
			{
				saveViewFeatures(); // [+] SSA
				shutdown(GuiUninit, NULL, true);
				_execl(WinUtil::getAppName().c_str(), WinUtil::getAppName().c_str(), "/c", NULL);
			}
			EndDialog(IDCANCEL);
			return 0;
		}
		
		
	private:
		LPEXCEPTION_POINTERS m_pException;
		bool m_bDumped;
		DWORD m_dwDumpError;
		std::unique_ptr<HIconWrapper> m_hIcon;
		CExceptionDlg(const CExceptionDlg&)
		{
			dcassert(0);
		};
		
};

#endif // !defined(EXCEPTION_DLG_H)
